home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Applications / Newswatcher 2.0b22 / NW Source / Source / ftp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-20  |  9.9 KB  |  379 lines  |  [TEXT/MMCC]

  1. /*----------------------------------------------------------------------------
  2.  
  3.     ftp.c
  4.  
  5.     This reusable module implements FTP text file transfers to and from memory.
  6.     
  7.     The following functions are exported:
  8.     
  9.         FtpOpen - Open an FTP stream.
  10.         FtpClose - Close an FTP stream.
  11.         FtpGetTextFile - Get a text file.
  12.         FtpSendTextFile - Send a text file.
  13.         
  14.     The following functions are used to get error information:
  15.         
  16.         FtpGetServerErrInfo - Get server error information.
  17.         FtpGetOSErr - Get OS error number.
  18.         
  19.     The NetInit function in module net.c must be called before calling any of
  20.     the functions in this module. You also must call the NetIdle function in your
  21.     idle loop, and the NetTerm function at program termination.
  22.         
  23.     A "stream" is an abstraction representing a bidirectional network connection
  24.     to an FTP server. A stream is represented as a handle of type "FtpStreamHandle". 
  25.     These stream handles are opaque. You may copy them and pass them as parameters 
  26.     to functions in ftp.c, but you are prohibited from accessing the contents of
  27.     the memory blocks pointed to by the stream handles. Only the functions in 
  28.     ftp.c are permitted to manipulate the contents of these blocks.
  29.     
  30.     The functions return a value of type FtpErr as the function result:
  31.     
  32.         ftpNoErr            no error occurred
  33.         ftpServerErr        server error
  34.         ftpOSErr            OS error
  35.         
  36.     If the function result is ftpServerErr, the FtpGetServerErrInfo function should
  37.     be called to get information about the server error. On server errors, the 
  38.     stream is still open on return to the caller (except in FtpOpen, which creates the
  39.     stream only if no errors of any kind occur).
  40.     
  41.     If the function result is ftpOSErr, the FtpGetOSErr function should be called
  42.     to get the OS error number:
  43.  
  44.         userCanceledErr        if the user canceled the operation
  45.         other                any other OS, Toolbox, or MacTCP error code
  46.         
  47.     If the user cancels an operation or any other OS error occurs, the stream
  48.     is aborted and deallocated before returning to the caller. "Aborted" means that 
  49.     the server connection is closed abruptly, without going through the usual TCP 
  50.     stream teardown process. You must perform careful error checking. The stream is
  51.     deallocated, and must not be reused.
  52.     
  53.     Copyright © 1994, Northwestern University.
  54.  
  55. ----------------------------------------------------------------------------*/
  56.  
  57. #include <stdlib.h>
  58. #include <string.h>
  59. #include <stdio.h>
  60.  
  61. #include "def.h"
  62. #include "ftp.h"
  63. #include "net.h"
  64. #include "memutil.h"
  65.  
  66.  
  67.  
  68. /* Types. */
  69.  
  70. typedef struct TStream {
  71.     NetStreamHandle netStream;                /* net stream handle */
  72. } TStream, *TStreamPtr, **TStreamHandle;
  73.  
  74.  
  75.  
  76. /*    Global variables. */
  77.  
  78. static OSErr gErr = noErr;            /* OS error code */
  79. static CStr255 gCommand = "";        /* server command */
  80. static long gResponseCode = 0;        /* server response code */
  81. static CStr255 gResponse = "";        /* server response message */
  82.  
  83.  
  84.  
  85. /*----------------------------------------------------------------------------
  86.     FtpOpen 
  87.     
  88.     Open an FTP stream.
  89.     
  90.     Entry:    host = server host address (domain name or dotted 
  91.                 decimal IP address).
  92.             username = user name.
  93.             password = password.
  94.     
  95.     Exit:    function result = result code.
  96.             stream = handle to opened stream,
  97.                 or nil if function result != ftpNoErr.
  98. ----------------------------------------------------------------------------*/
  99.  
  100. FtpErr FtpOpen (char *host, char *username, char *password,
  101.     FtpStreamHandle *stream)
  102. {
  103.     TStreamHandle s;
  104.     unsigned long addr;
  105.     unsigned short port;
  106.     NetStreamHandle netStream;
  107.     
  108.     *stream = nil;
  109.     *gCommand = 0;
  110.  
  111.     gErr = NetNameToAddr(host, kFTPPort, &addr, &port);
  112.     if (gErr != noErr) return ftpOSErr;
  113.     
  114.     gErr = NetOpen(addr, port, &netStream, &gResponseCode, gResponse);
  115.     if (gErr != noErr) return ftpOSErr;
  116.     if (gResponseCode != 220) goto exit1;
  117.         
  118.     sprintf(gCommand, "USER %.250s", username);
  119.     gErr = NetCommand(netStream, gCommand, &gResponseCode, gResponse);
  120.     if (gErr != noErr) return ftpOSErr;
  121.     if (gResponseCode != 331) goto exit1;
  122.     
  123.     sprintf(gCommand, "PASS %.250s", password);
  124.     gErr = NetCommand(netStream, gCommand, &gResponseCode, gResponse);
  125.     if (gErr != noErr) return ftpOSErr;
  126.     if (gResponseCode != 230) goto exit1;
  127.     
  128.     gErr = MyNewHandle(sizeof(TStream), &s);
  129.     if (gErr != noErr) goto exit2;
  130.     
  131.     (**s).netStream = netStream;
  132.     *stream = (FtpStreamHandle)s;
  133.     return ftpNoErr;
  134.     
  135. exit1:
  136.  
  137.     NetClose(netStream);
  138.     return ftpServerErr;
  139.     
  140. exit2:
  141.  
  142.     NetClose(netStream);
  143.     return ftpOSErr;
  144. }
  145.  
  146.  
  147.  
  148. /*----------------------------------------------------------------------------
  149.     FtpClose 
  150.     
  151.     Close an FTP stream.
  152.     
  153.     Entry:    stream = handle to stream.
  154.     
  155.     Exit:    function result = result code (always ftpNoErr).
  156. ----------------------------------------------------------------------------*/
  157.  
  158. FtpErr FtpClose (FtpStreamHandle stream)
  159. {
  160.     TStreamHandle s;
  161.     
  162.     s = (TStreamHandle)stream;
  163.     NetClose((**s).netStream);
  164.     MyDisposeHandle(s);
  165.     return ftpNoErr;
  166. }
  167.  
  168.  
  169.  
  170. /*----------------------------------------------------------------------------
  171.     FtpGetTextFile 
  172.     
  173.     Get a text file from an FTP server.
  174.     
  175.     Entry:    stream = handle to stream.
  176.             path = file path.
  177.     
  178.     Exit:    function result = result code.
  179.             text = handle to text.
  180.             
  181.     The text block contains CR line terminators, including a CR terminator
  182.     at the end of the last line.
  183. ----------------------------------------------------------------------------*/
  184.  
  185. FtpErr FtpGetTextFile (FtpStreamHandle stream, char *path, Handle *text)
  186. {
  187.     TStreamHandle s;
  188.     NetStreamHandle controlStream, dataStream;
  189.     unsigned long myAddr;
  190.     unsigned short port;
  191.     
  192.     s = (TStreamHandle)stream;
  193.     controlStream = (**s).netStream;
  194.     
  195.     gErr = NetGetMyAddr(&myAddr);
  196.     if (gErr != noErr) goto exit1;
  197.     
  198.     gErr = NetFTPDataOpen(&port, &dataStream);
  199.     if (gErr != noErr) goto exit1;
  200.     
  201.     sprintf(gCommand, "PORT %hu,%hu,%hu,%hu,%hu,%hu",
  202.         (unsigned short)((myAddr>>24)&0xff), 
  203.         (unsigned short)((myAddr>>16)&0xff), 
  204.         (unsigned short)((myAddr>>8)&0xff), 
  205.         (unsigned short)(myAddr&0xff),
  206.         (unsigned short)((port>>8)&0xff), 
  207.         (unsigned short)(port&0xff));
  208.     gErr = NetCommand(controlStream, gCommand, &gResponseCode, gResponse);
  209.     if (gErr != noErr) goto exit2; 
  210.     if (gResponseCode != 200) goto exit3;
  211.     
  212.     sprintf(gCommand, "RETR %.250s", path);
  213.     gErr = NetCommand(controlStream, gCommand, &gResponseCode, gResponse);
  214.     if (gErr != noErr) goto exit2;
  215.     if (gResponseCode != 150 && gResponseCode != 125) goto exit3;
  216.     
  217.     gErr = NetFTPDataWaitForConnection(dataStream);
  218.     if (gErr != noErr) goto exit1;
  219.     
  220.     gErr = NetGetFTPTextFile(dataStream, text);
  221.     if (gErr != noErr) goto exit1;
  222.     
  223.     gErr = NetFTPDataClose(dataStream);
  224.     if (gErr != noErr) goto exit1;
  225.     
  226.     gErr = NetGetExtraResponse(controlStream, &gResponseCode, gResponse);
  227.     if (gErr != noErr) goto exit4;
  228.     if (gResponseCode != 226) return ftpServerErr;
  229.     
  230.     return ftpNoErr;
  231.     
  232. exit1:
  233.  
  234.     NetClose(controlStream);
  235.     MyDisposeHandle(s);
  236.     return ftpOSErr;
  237.     
  238. exit2:
  239.  
  240.     NetFTPDataClose(dataStream);
  241.     MyDisposeHandle(s);
  242.     return ftpOSErr;
  243.     
  244. exit3:
  245.  
  246.     NetFTPDataClose(dataStream);
  247.     return ftpServerErr;
  248.     
  249. exit4:
  250.  
  251.     MyDisposeHandle(s);
  252.     return ftpOSErr;
  253. }
  254.  
  255.  
  256.  
  257. /*----------------------------------------------------------------------------
  258.     FtpSendTextFile 
  259.     
  260.     Send a text file to an FTP server.
  261.     
  262.     Entry:    stream = handle to stream.
  263.             path = file path.
  264.             text = handle to text.
  265.     
  266.     Exit:    function result = result code.
  267.     
  268.     The text must contain CR line terminators. If the last line is
  269.     not terminated with a CR, an extra CR terminator is added.
  270.     
  271.     The CR line terminators are converted to CRLF when the file is sent
  272.     over the network to the server. The server converts the CRLF line
  273.     terminators to whatever terminator is used on the host system.
  274. ----------------------------------------------------------------------------*/
  275.  
  276. FtpErr FtpSendTextFile (FtpStreamHandle stream, char *path, Handle text)
  277. {
  278.     TStreamHandle s;
  279.     NetStreamHandle controlStream, dataStream;
  280.     unsigned long myAddr;
  281.     unsigned short port;
  282.     
  283.     s = (TStreamHandle)stream;
  284.     controlStream = (**s).netStream;
  285.     
  286.     gErr = NetGetMyAddr(&myAddr);
  287.     if (gErr != noErr) goto exit1;
  288.     
  289.     gErr = NetFTPDataOpen(&port, &dataStream);
  290.     if (gErr != noErr) goto exit1;
  291.     
  292.     sprintf(gCommand, "PORT %hu,%hu,%hu,%hu,%hu,%hu",
  293.         (unsigned short)((myAddr>>24)&0xff), 
  294.         (unsigned short)((myAddr>>16)&0xff), 
  295.         (unsigned short)((myAddr>>8)&0xff), 
  296.         (unsigned short)(myAddr&0xff),
  297.         (unsigned short)((port>>8)&0xff), 
  298.         (unsigned short)(port&0xff));
  299.     gErr = NetCommand(controlStream, gCommand, &gResponseCode, gResponse);
  300.     if (gErr != noErr) goto exit2; 
  301.     if (gResponseCode != 200) goto exit3;
  302.     
  303.     sprintf(gCommand, "STOR %.250s", path);
  304.     gErr = NetCommand(controlStream, gCommand, &gResponseCode, gResponse);
  305.     if (gErr != noErr) goto exit2;
  306.     if (gResponseCode != 150 && gResponseCode != 125) goto exit3;
  307.     
  308.     gErr = NetFTPDataWaitForConnection(dataStream);
  309.     if (gErr != noErr) goto exit1;
  310.     
  311.     gErr = NetSendFTPTextFile(dataStream, text);
  312.     if (gErr != noErr) goto exit1;
  313.     
  314.     gErr = NetFTPDataClose(dataStream);
  315.     if (gErr != noErr) goto exit1;
  316.     
  317.     gErr = NetGetExtraResponse(controlStream, &gResponseCode, gResponse);
  318.     if (gErr != noErr) goto exit4;
  319.     if (gResponseCode != 226) return ftpServerErr;
  320.     
  321.     return ftpNoErr;
  322.     
  323. exit1:
  324.  
  325.     NetClose(controlStream);
  326.     MyDisposeHandle(s);
  327.     return ftpOSErr;
  328.     
  329. exit2:
  330.  
  331.     NetFTPDataClose(dataStream);
  332.     MyDisposeHandle(s);
  333.     return ftpOSErr;
  334.     
  335. exit3:
  336.  
  337.     NetFTPDataClose(dataStream);
  338.     return ftpServerErr;
  339.     
  340. exit4:
  341.  
  342.     MyDisposeHandle(s);
  343.     return ftpOSErr;
  344. }
  345.  
  346.  
  347.  
  348. /*----------------------------------------------------------------------------
  349.     FtpGetServerErrInfo 
  350.     
  351.     Get server error information.
  352.     
  353.     Exit:    cmd = C-format server command.
  354.             num = server error number.
  355.             msg = C-format server error message.
  356. ----------------------------------------------------------------------------*/
  357.  
  358. void FtpGetServerErrInfo (CStr255 cmd, long *num, CStr255 msg)
  359. {
  360.     strcpy(cmd, gCommand);
  361.     *num = gResponseCode;
  362.     strcpy(msg, gResponse);
  363. }
  364.  
  365.  
  366.  
  367. /*----------------------------------------------------------------------------
  368.     FtpGetOSErr 
  369.     
  370.     Get the OS error code.
  371.     
  372.     Exit:    function result = OS error code.
  373. ----------------------------------------------------------------------------*/
  374.  
  375. OSErr FtpGetOSErr (void)
  376. {
  377.     return gErr;
  378. }
  379.